﻿using System;
using System.Text;

using LeanEngine.Extensions;
using LeanEngine.Exception;

namespace LeanEngine.Validation
{
    /// <summary>
    /// Attribute to validate if a property has a not empty string
    /// </summary>
    [AttributeUsage(AttributeTargets.Property, AllowMultiple = false)]
    public sealed class IsNotEmptyAttribute : ValidationAttribute
    {
        #region PropertyInfo Members

        /// <summary>
        /// Gets the maximun length expected
        /// </summary>
        public int MaxLength
        {
            get;
            private set;
        }
        
        #endregion

        #region Constructor Members

        /// <summary>
        /// Initialize a new instance with an error message obtained from a resource.
        /// </summary>
        /// <param name="resourceType">Type of the resource manager that contain the error message</param>
        /// <param name="errorKey">Resource item key for the error message</param>
        public IsNotEmptyAttribute(Type resourceType, string errorKey)
            : base(resourceType, errorKey) { }

        /// <summary>
        /// Initialize a new instance with an error message.
        /// </summary>
        /// <param name="errorMessage">The error message displayed for non valid values.</param>
        public IsNotEmptyAttribute(string errorMessage)
            : base(errorMessage) { }

        /// <summary>
        /// Initialize a new instance with an error message obtained from a resource.
        /// </summary>
        /// <param name="maxLength">The maximum string length for the string.</param>
        /// <param name="resourceType">Type of the resource manager that contain the error message</param>
        /// <param name="errorKey">Resource item key for the error message</param>
        public IsNotEmptyAttribute(int maxLength, Type resourceType, string errorKey)
            : base(resourceType, errorKey) 
        {
            this.MaxLength = maxLength;
        }

        /// <summary>
        /// Initialize a new instance with an error message.
        /// </summary>
        /// <param name="maxLength">The maximum string length for the string.</param>
        /// <param name="errorMessage">The error message displayed for non valid values.</param>
        public IsNotEmptyAttribute(int maxLength, string errorMessage)
            : base(errorMessage) 
        {
            this.MaxLength = maxLength;
        }

        #endregion

        #region ValidationAttribute Members

        /// <summary>
        /// Validates the value according to the validation rule and throws an exception in case of validation failure.
        /// </summary>
        /// <exception cref="LeanEngine.Exception.BusinessException"></exception>
        /// <exception cref="System.ArgumentException"></exception>
        /// <param name="value">The value to be validated.</param>
        public override bool Validate(object value)
        {
            if (value.IsNull() ||
                value.ChangeType<string>().IsNullOrEmpty() ||
                (this.MaxLength.IsGreaterThan(0) &&
                 value.ToString().Length.IsGreaterThan(this.MaxLength)))
            {
                throw new BusinessException(this.ErrorMessage);
            }

            return true;
        }

        /// <summary>
        /// Validates the value according to the validation rule to the container and adds exception error in case of validation failure.
        /// </summary>
        /// <param name="value">The value to be validated.</param>
        /// <param name="errorMessageContainer">The container for all the error messages.</param>
        public override void Validate(object value, StringBuilder errorMessageContainer)
        {
            if (value.IsNull() ||
                value.ChangeType<string>().IsNullOrEmpty() ||
                (this.MaxLength.IsGreaterThan(0) &&
                 value.ToString().Length.IsGreaterThan(this.MaxLength)))
            {
                errorMessageContainer.Append(this.ErrorMessage);
                errorMessageContainer.Append(Environment.NewLine);
            }
        }

        #endregion
    }
}
